using HybridCLR;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;

namespace LFrameworkAOT
{
    /// <summary>
    /// 代码热更新控制器
    /// </summary>
    public class HotfixCtrl
    {
        public static HotfixCtrl Instance { get; private set; } = new();

        //热更dll 名称
        public static string HotfixDllName = "Assembly-CSharp";
        //
        private AllAssetsHandle m_AssetHandle;
        public static List<string> AotMetaAssemblyFiles = new List<string>()
        {
            "mscorlib",
            "System",
            "System.Core",
            "UnityEngine.CoreModule",
        };

        public HotfixCtrl()
        {
            //这里防止热更工程找不到AOT工程的类
            //System.Data.AcceptRejectRule acceptRejectRule = System.Data.AcceptRejectRule.None;
            //System.Net.WebSockets.WebSocketReceiveResult webSocketReceiveResult = null;
        }

        public IEnumerator LoadHotifx()
        {
#if !UNITY_EDITOR
            m_AssetHandle = YooAssets.LoadAllAssetsAsync<TextAsset>("Assets/Download/Hotfix/" + HotfixDllName + ".dll.bytes");
            yield return m_AssetHandle;

            LoadMetadataForAOTAssemblies();

            //加载热更Dll
            TextAsset hotfixAsset = GetDllByNames(HotfixDllName + ".dll");
            if (hotfixAsset != null)
            {
                System.Reflection.Assembly.Load(hotfixAsset.bytes);
                MainEntry.Log(HotfixDllName , "加载完毕");
            }
            else 
            {
                MainEntry.Log(HotfixDllName ,"加载为 null");
            }
#else
            yield return null;
#endif
        }

        /// <summary>
        /// 为aot assembly加载原始metadata， 这个代码放aot或者热更新都行。
        /// 一旦加载后，如果AOT泛型函数对应native实现不存在，则自动替换为解释模式执行
        /// </summary>
        private void LoadMetadataForAOTAssemblies()
        {
            /// 注意，补充元数据是给AOT dll补充元数据，而不是给热更新dll补充元数据。
            /// 热更新dll不缺元数据，不需要补充，如果调用LoadMetadataForAOTAssembly会返回错误
            /// 
            HomologousImageMode mode = HomologousImageMode.SuperSet;
            foreach (var aotDllName in AotMetaAssemblyFiles)
            {
                TextAsset textAsset = GetDllByNames(aotDllName + ".dll");
                if (textAsset == null) 
                {
                    GameLaunch.Log("补充元数据Dll 是null==" , aotDllName);
                    continue;
                }
                    
                // 加载assembly对应的dll，会自动为它hook。一旦aot泛型函数的native函数不存在，用解释器版本代码
                LoadImageErrorCode err = RuntimeApi.LoadMetadataForAOTAssembly(textAsset.bytes, mode);
            }
            GameLaunch.Log("补充元数据Dll加载完毕==" , AotMetaAssemblyFiles);
        }

        /// <summary>
        /// 从asset 中获取dll
        /// </summary>
        /// <param name="dllName"></param>
        /// <returns></returns>
        private TextAsset GetDllByNames(string dllName) 
        {
            foreach (var assetObj in m_AssetHandle.AllAssetObjects)
            {
                UnityEngine.TextAsset textAsset = assetObj as UnityEngine.TextAsset;
                if(textAsset.name.Equals(dllName))
                    return textAsset;
            }
            return null;
        }

        /// <summary>
        /// 释放 热更代码
        /// </summary>
        public void ReleaseHotfix() 
        {
            if (m_AssetHandle != null) 
            {
                if(m_AssetHandle.IsDone)
                    m_AssetHandle.Release();
                m_AssetHandle = null;
            }
        }
    }
}